package com.rxyb.wechat.utils;

import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import com.rxyb.toolize.VO;
import com.rxyb.wechat.utils.bean.ReceiveXmlEntity;
import com.rxyb.wechat.utils.bean.WechatNewsEntity;
import com.rxyb.wechat.utils.bean.WechatNewsVo;
import com.thoughtworks.xstream.XStream;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 解析微信XML
 *
 * @coder duyh,@auth duyh
 * @date May 18, 2020
 */
@Slf4j
public class EntranceService {

    /**
     * 解析微信xml消息
     *
     * @param reqXmlCrt
     * @return
     */
    public Optional<ReceiveXmlEntity> analysis(Map<String, String> map, String reqXmlCrt) {
        try {
            String token = map.get("token");
            String appId = map.get("appId");
            String encodingAeskey = map.get("encodingAeskey");
            if (VO.isNotBlank(token) && VO.isNotBlank(appId) && VO.isNotBlank(encodingAeskey)) {
                WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAeskey, appId);
                /* 密文记录 */
                log.info("解密前密文: " + reqXmlCrt);
                String timestamp = map.get("timestamp");
                String msgSignature = map.get("msg_signature");
                String nonce = map.get("nonce");
                reqXmlCrt = pc.decryptMsg(msgSignature, timestamp, nonce, reqXmlCrt);
                log.info("解密后明文: " + reqXmlCrt);
            }
            log.info(this.hashCode() + "收到的请求：" + reqXmlCrt);
            ReceiveXmlEntity recEn = getMsgEntity(reqXmlCrt, ReceiveXmlEntity.class);
            return Optional.of(recEn);
        } catch (Exception e) {
            log.error("异常：", e);
            return Optional.empty();
        }
    }


    /**
     * 内容处理
     *
     * @param recEn
     * @param newsList 图文消息列表
     * @param cont     文字回复内容
     * @return
     */
    public String deal(ReceiveXmlEntity recEn, List<WechatNewsVo> newsList, String cont) {
        //        FormatXmlProcess rspPro = new FormatXmlProcess();
        String result = "success";
        if ("event".equals(recEn.getMsgType())) {
            if ("subscribe".equals(recEn.getEvent())) {
                result = formatXmlAnswer(recEn.getFromUserName(), recEn.getToUserName(), cont);
                // 用户openId
                log.info("用户【{}】关注【{}】：", recEn.getFromUserName(), recEn.getToUserName());
            } else if ("unsubscribe".equals(recEn.getEvent())) {
                log.info("用户【{}】取关【{}】：", recEn.getFromUserName(), recEn.getToUserName());
            } else if ("CLICK".equals(recEn.getEvent())) {
                if (null != newsList || newsList.size() > 0) {
                    WechatNewsEntity newsMessage = ImageNewsUtils.initWechatNewsEntity(newsList);
                    newsMessage.setFromUserName(recEn.getToUserName());
                    newsMessage.setToUserName(recEn.getFromUserName());
                    result = newsMessageToXml(newsMessage);
                } else {
                    result = formatXmlAnswer(recEn.getFromUserName(), recEn.getToUserName(), "这是小程序检验机构");
                }
            } else {
                log.info("这是个什么事件：event=【{}】,FromUserName=【{}】", recEn.getEvent(), recEn.getFromUserName());
            }
        } else if ("text".equals(recEn.getMsgType())) {
            result = formatXmlAnswer(recEn.getFromUserName(), recEn.getToUserName(), cont);
        }
        return result;
    }

    /**
     * 解析微信xml消息
     *
     * @param strXml
     * @return
     */
    private ReceiveXmlEntity getMsgEntity(String strXml, Class<?> c) {
        ReceiveXmlEntity msg = null;
        try {
            if (strXml.length() <= 0 || strXml == null)
                return null;
            // 将字符串转化为XML文档对象
            Document document = DocumentHelper.parseText(strXml);
            // 获得文档的根节点
            Element root = document.getRootElement();
            // 遍历根节点下所有子节点
            Iterator<?> iter = root.elementIterator();

            // 遍历所有结点
            msg = new ReceiveXmlEntity();
            // 利用反射机制，调用set方法
            // 获取该实体的元类型
            // Class<?> c = Class.forName("com.huapay.kxd.wechat.ReceiveXmlEntity");
            msg = (ReceiveXmlEntity) c.newInstance();// 创建这个实体的对象

            while (iter.hasNext()) {
                try {
                    Element ele = (Element) iter.next();
                    // 获取set方法中的参数字段（实体类的属性）
                    Field field = c.getDeclaredField(ele.getName());
                    // 获取set方法，field.getType())获取它的参数数据类型
                    Method method = c.getDeclaredMethod("set" + ele.getName(), field.getType());
                    // 调用set方法
                    method.invoke(msg, ele.getText());
                } catch (Exception e) {
                }
            }
        } catch (Exception e) {
            // handle exception
            System.err.println("xml 格式异常: " + strXml);
            e.printStackTrace();
        }
        return msg;
    }


    /**
     * 封装文字类的返回消息
     *
     * @param to
     * @param from
     * @param content
     * @return
     */
    private String formatXmlAnswer(String to, String from, String content) {
        StringBuffer sb = new StringBuffer();
        Date date = new Date();
        sb.append("<xml><ToUserName><![CDATA[");
        sb.append(to);
        sb.append("]]></ToUserName><FromUserName><![CDATA[");
        sb.append(from);
        sb.append("]]></FromUserName><CreateTime>");
        sb.append(date.getTime());
        sb.append("</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[");
        sb.append(content);
        sb.append("]]></Content><FuncFlag>0</FuncFlag></xml>");
        return sb.toString();
    }

    /**
     * 封装图文的返回消息
     *
     * @param newsMessage
     * @return
     */
    private String newsMessageToXml(WechatNewsEntity newsMessage) {
        XStream xstream = new XStream();
        xstream.alias("xml", newsMessage.getClass());
        xstream.alias("item", new WechatNewsVo().getClass());
        return xstream.toXML(newsMessage);

    }

    private String formatXmlNews(String to, String from, List<WechatNewsVo> list) {
        StringBuffer sb = new StringBuffer();
        Date date = new Date();
        sb.append("<xml><ToUserName><![CDATA[");
        sb.append(to);
        sb.append("]]></ToUserName><FromUserName><![CDATA[");
        sb.append(from);
        sb.append("]]></FromUserName><CreateTime>");
        sb.append(date.getTime());
        sb.append("</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount>");
        sb.append(list.size());
        sb.append("</ArticleCount><Articles>");
        for (int i = 0; i < list.size(); i++) {
            sb.append("<item><Title>< ![CDATA[");
            sb.append(list.get(i).getTitle());
            sb.append("] ]></Title><Description>< ![CDATA[");
            sb.append(list.get(i).getDescription());
            sb.append("] ]></Description><PicUrl>< ![CDATA[");
            sb.append(list.get(i).getPicUrl());
            sb.append("] ]></PicUrl><Url>< ![CDATA[");
            sb.append(list.get(i).getUrl());
            sb.append("] ]></Url></item>");
        }
        sb.append("</Articles></xml>");
        return sb.toString();
    }

}
